home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume17 / zoo2 / part05 < prev    next >
Encoding:
Internet Message Format  |  1989-02-01  |  41.5 KB

  1. Subject:  v17i068:  Zoo archive program, Part05/10
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4.  
  5. Submitted-by: Rahul Dhesi <bsu-cs!dhesi@iuvax.cs.indiana.edu>
  6. Posting-number: Volume 17, Issue 68
  7. Archive-name: zoo2/part05
  8.  
  9. #! /bin/sh
  10. # This is a shell archive.  Remove anything before this line, then unpack
  11. # it by saving it into a file and typing "sh file".  To overwrite existing
  12. # files, type "sh file -c".  You can also feed this as standard input via
  13. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  14. # will see the following message at the end:
  15. #        "End of archive 5 (of 10)."
  16. # Wrapped by rsalz@papaya.bbn.com on Thu Feb  2 18:04:00 1989
  17. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  18. if test -f 'comment.c' -a "${1}" != "-c" ; then 
  19.   echo shar: Will not clobber existing file \"'comment.c'\"
  20. else
  21. echo shar: Extracting \"'comment.c'\" \(9637 characters\)
  22. sed "s/^X//" >'comment.c' <<'END_OF_FILE'
  23. X#ifndef LINT
  24. Xstatic char sccsid[]="@(#) comment.c 2.14 88/01/24 12:42:13";
  25. X#endif /* LINT */
  26. X
  27. X/*
  28. XCopyright (C) 1986, 1987 Rahul Dhesi -- All rights reserved
  29. X(C) Copyright 1988 Rahul Dhesi -- All rights reserved
  30. X*/
  31. X
  32. X#include "options.h"
  33. X#include "portable.h"
  34. X/* comment() */
  35. X/* Updates comments */
  36. X
  37. X/* buffer size for any one comment line */
  38. X#define  COMMENT_LINE_SIZE 76
  39. X
  40. X#define  MAX_COMMENT_SIZE  65535
  41. X#include "zooio.h"
  42. X#include "various.h"
  43. X
  44. X#ifndef NOSIGNAL
  45. X#include <signal.h>
  46. X#endif
  47. X
  48. X#include "zoo.h"
  49. X#include "zoofns.h"
  50. X#include "errors.i"
  51. X
  52. X#ifdef LINT_ARGS
  53. Xvoid show_comment (struct direntry *, ZOOFILE, int, char *);
  54. Xget_comment (struct direntry *, ZOOFILE, char *);
  55. Xint needed (char *, struct direntry *, struct zoo_header *);
  56. X#else
  57. Xvoid show_comment ();
  58. Xget_comment ();
  59. Xint needed ();
  60. X#endif
  61. X
  62. Xvoid comment(zoo_path, option)
  63. Xchar *zoo_path, *option;
  64. X{
  65. X#ifndef NOSIGNAL  
  66. Xint (*oldsignal)();
  67. X#endif
  68. XZOOFILE zoo_file;                         /* stream for open archive */
  69. Xlong next_ptr;                            /* pointers to within archive */
  70. Xlong this_dir_offset;                     /* pointers to within archive */
  71. Xstruct direntry direntry;                 /* directory entry */
  72. Xstruct zoo_header zoo_header;
  73. Xint matched = 0;                          /* any files matched? */
  74. Xunsigned int zoo_date, zoo_time;          /* for restoring archive timestamp */
  75. Xchar whichname[PATHSIZE];                 /* which name to use */
  76. X#ifdef ZOOCOMMENT
  77. Xint acmt = 0;                                        /* if changing archive comment */
  78. X#endif
  79. X
  80. X/* on entry option points to first letter */
  81. Xoption++;                                            /* skip 'c' */
  82. X#ifdef ZOOCOMMENT
  83. Xwhile (*option != '\0') {
  84. X    if (*option == 'A') {
  85. X        acmt++;                                        /* changing archive comment */
  86. X        option++;
  87. X    } else
  88. X       prterror ('f', inv_option, *option);
  89. X}
  90. X#else
  91. Xif (*option != '\0')
  92. X    prterror ('f', inv_option, *option);
  93. X#endif /* ZOOCOMMENT */
  94. X
  95. Xif ((zoo_file = zooopen (zoo_path, Z_RDWR)) == NOFILE)
  96. X   prterror ('f', could_not_open, zoo_path);
  97. X
  98. X/* save archive timestamp */
  99. X#ifdef GETUTIME
  100. Xgetutime (zoo_path, &zoo_date, &zoo_time);
  101. X#else
  102. Xgettime (zoo_file, &zoo_date, &zoo_time);
  103. X#endif
  104. X
  105. X/* read header and rewrite with updated version numbers, but ask user to pack
  106. Xarchive first if archive comment is to be added and header type is 0 */
  107. X#ifdef ZOOCOMMENT
  108. Xif (acmt)
  109. X    rwheader (&zoo_header, zoo_file, 0);
  110. Xelse
  111. X    rwheader (&zoo_header, zoo_file, 1);
  112. X#else
  113. Xrwheader (&zoo_header, zoo_file, 1);
  114. X#endif
  115. X
  116. X#ifdef ZOOCOMMENT
  117. X/* if archive comment being added, handle it and return */
  118. Xif (acmt) {
  119. X    void do_acmt PARMS ((struct zoo_header *, ZOOFILE, char *));
  120. X    do_acmt (&zoo_header, zoo_file, zoo_path);
  121. X#ifdef NIXTIME
  122. X    zooclose (zoo_file);
  123. X    setutime (zoo_path, zoo_date, zoo_time);    /* restore timestamp */
  124. X#else
  125. X    settime (zoo_file, zoo_date, zoo_time);    /* restore timestamp */
  126. X    zooclose (zoo_file);
  127. X#endif
  128. X    return;
  129. X}
  130. X#endif /* ZOOCOMMENT */
  131. X
  132. X/* Loop through and add comments for matching files */
  133. Xwhile (1) {
  134. X   this_dir_offset = zootell (zoo_file);  /* save pos'n of this dir entry */
  135. X   readdir (&direntry, zoo_file, 1);      /* read directory entry */
  136. X   next_ptr = direntry.next;              /* ptr to next dir entry */
  137. X
  138. X   /* exit on end of directory chain or end of file */
  139. X   if (next_ptr == 0L || feof(stdin))
  140. X      break;
  141. X
  142. X    strcpy (whichname, fullpath (&direntry));        /* full pathname */
  143. X    add_version (whichname, &direntry);                /* add version suffix */
  144. X   /* add comments for matching non-deleted files */
  145. X   if (!direntry.deleted && needed (whichname, &direntry, &zoo_header)) {
  146. X      matched++;
  147. X      show_comment (&direntry, zoo_file, 1, whichname);
  148. X      get_comment (&direntry, zoo_file, whichname);
  149. X      zooseek (zoo_file, this_dir_offset, 0);
  150. X#ifndef NOSIGNAL
  151. X      oldsignal = signal (SIGINT, SIG_IGN);
  152. X#endif
  153. X      fwr_dir (&direntry, zoo_file);
  154. X#ifndef NOSIGNAL
  155. X      signal (SIGINT, oldsignal);
  156. X#endif
  157. X   }
  158. X   zooseek (zoo_file, next_ptr, 0);   /* ..seek to next dir entry */
  159. X} /* end while */
  160. X
  161. X#ifdef NIXTIME
  162. Xzooclose (zoo_file);
  163. Xsetutime (zoo_path, zoo_date, zoo_time);    /* restore timestamp */
  164. X#else
  165. Xsettime (zoo_file, zoo_date, zoo_time);    /* restore timestamp */
  166. Xzooclose (zoo_file);
  167. X#endif
  168. X
  169. Xif (!matched)
  170. X   printf ("Zoo:  %s", no_match);
  171. X} /* comment */
  172. X
  173. X/* show_comment() */
  174. X/* shows comment on screen.  If show=1, says "Current comment is..." */
  175. X
  176. Xvoid show_comment (direntry, zoo_file, show, name)
  177. Xstruct direntry *direntry;
  178. XZOOFILE zoo_file;
  179. Xint show;
  180. Xchar *name;       /* name of file for which comment is being added */
  181. X{
  182. X   if (direntry->cmt_size != 0) {
  183. X      unsigned int i;
  184. X      char ch;
  185. X      int newline = 1;
  186. X      zooseek (zoo_file, direntry->comment, 0);   
  187. X      if (show)
  188. X         printf ("Current comment for %s is:\n", name);
  189. X      for (i = 0; i < direntry->cmt_size; i++) {/* show it */
  190. X         ch = zgetc (zoo_file) & 0x7f;          /* 7 bits only */
  191. X         if (newline)
  192. X            printf (" |");    /* indent and mark comment lines thus */
  193. X         zputchar (ch);
  194. X         if (ch == '\n')
  195. X            newline = 1;
  196. X         else
  197. X            newline = 0;
  198. X      }
  199. X      if (!newline)              /* always terminate with newline */
  200. X         zputchar ('\n');
  201. X   }
  202. X} /* show_comment() */
  203. X
  204. X
  205. X/* get_comment() */
  206. X/* Shows user old comment and updates it */
  207. X
  208. X/* INPUT:
  209. X   direntry points to current directory entry.
  210. X   zoo_file is archive file.
  211. X   this_path is full pathname of file being updated/added.
  212. X
  213. X   OUTPUT:
  214. X   Comment is added to file and supplied directory entry is updated
  215. X   with comment size and seek position but directory entry is
  216. X   not written to file.  Exceptions:  If RETURN is hit as first line,
  217. X   previous comment is left unchanged.  If /END is hit, previous
  218. X   comment is superseded, even if new comment is null.
  219. X*/
  220. X
  221. Xchar cmt_prompt[]="[Enter %scomment for %s then type /END]\n";
  222. X
  223. Xget_comment (direntry, zoo_file, this_path)  /* update comment */
  224. Xregister struct direntry *direntry;
  225. XZOOFILE zoo_file;
  226. Xchar *this_path;
  227. X{
  228. X   unsigned int line_count = 0;        /* count of new comment lines */
  229. X
  230. X   zooseek (zoo_file, 0L, 2);            /* ready to append new comment */
  231. X#if 0
  232. X   fprintf (stderr, "[Enter comment for %s then type /END]\n", this_path);
  233. X#else
  234. X   fprintf (stderr, cmt_prompt, "", this_path);
  235. X#endif
  236. X   while (1) {
  237. X      char cmt_line[COMMENT_LINE_SIZE];
  238. X      int cmt_size;
  239. X      if (fgets (cmt_line, sizeof(cmt_line), stdin) == NULL)
  240. X         break;
  241. X      line_count++;
  242. X      if (line_count == 1) {                 /* first line typed */
  243. X         if (!strcmp (cmt_line, "\n"))   /* exit if first line blank */
  244. X            break;
  245. X         direntry->comment = zootell (zoo_file);
  246. X         direntry->cmt_size = 0;
  247. X      }
  248. X      if (!strcmpi (cmt_line, "/end\n"))
  249. X         break;
  250. X      cmt_size = strlen (cmt_line);
  251. X      if (MAX_COMMENT_SIZE - direntry->cmt_size > cmt_size) {
  252. X         direntry->cmt_size += (unsigned int) cmt_size;
  253. X         if (zoowrite (zoo_file, cmt_line, cmt_size) < cmt_size)
  254. X            prterror ('f', disk_full);
  255. X      }
  256. X   } /* end while */
  257. X} /* get_comment() */
  258. X
  259. X#ifdef ZOOCOMMENT
  260. X/*
  261. Xdo_acmt() updates archive comment by showing it to user and 
  262. Xrequesting a new one.  Typed input terminates as with file comment,
  263. Xi.e., empty initial line leaves comment unchanged, case-insensitive
  264. X"/end" terminates input comment.
  265. X*/
  266. Xvoid do_acmt (zoo_header, zoo_file, zoo_path)
  267. Xstruct zoo_header *zoo_header;
  268. XZOOFILE zoo_file;
  269. Xchar *zoo_path;
  270. X{
  271. X   unsigned int line_count = 0;        /* count of new comment lines */
  272. X    void show_acmt PARMS ((struct zoo_header *, ZOOFILE, int));
  273. X
  274. X    show_acmt (zoo_header, zoo_file, 1);    /* show current archive comment */
  275. X   zooseek (zoo_file, 0L, 2);            /* ready to append new comment */
  276. X#if 0
  277. X   fprintf (stderr, "[Enter archive comment for %s then type /END]\n", 
  278. X                            zoo_path);
  279. X#else
  280. X   fprintf (stderr, cmt_prompt, "archive ", zoo_path);
  281. X#endif
  282. X
  283. X   while (1) {
  284. X      char cmt_line[COMMENT_LINE_SIZE];
  285. X      int cmt_size;
  286. X      if (fgets (cmt_line, sizeof(cmt_line), stdin) == NULL)
  287. X         break;
  288. X      line_count++;
  289. X      if (line_count == 1) {                 /* first line typed */
  290. X         if (!strcmp (cmt_line, "\n"))   /* exit if first line blank */
  291. X            break;
  292. X         zoo_header->acmt_pos = zootell (zoo_file);
  293. X         zoo_header->acmt_len = 0;
  294. X      }
  295. X      if (!strcmpi (cmt_line, "/end\n"))
  296. X         break;
  297. X      cmt_size = strlen (cmt_line);
  298. X      if (MAX_COMMENT_SIZE - zoo_header->acmt_len > cmt_size) {
  299. X         zoo_header->acmt_len += (unsigned int) cmt_size;
  300. X         if (zoowrite (zoo_file, cmt_line, cmt_size) < cmt_size)
  301. X            prterror ('f', disk_full);
  302. X      }
  303. X   } /* end while */
  304. X    zooseek (zoo_file, 0L, 0);                    /* seek back to beginning */
  305. X    fwr_zooh (zoo_header, zoo_file);            /* write update zoo_header */
  306. X} /* do_acmt() */
  307. X#endif /* ZOOCOMMENT */
  308. X
  309. X/* Prints archive comment.  If show==1, says "Current archive comment is:" */
  310. Xvoid show_acmt (zoo_header, zoo_file, show)
  311. Xstruct zoo_header *zoo_header;
  312. XZOOFILE zoo_file;
  313. Xint show;
  314. X{
  315. X   if (zoo_header->zoo_start != FIXED_OFFSET && zoo_header->acmt_len > 0) {
  316. X      unsigned int i;
  317. X      char ch;
  318. X      int newline = 1;
  319. X      zooseek (zoo_file, zoo_header->acmt_pos, 0);   
  320. X        if (show)
  321. X          printf ("Current archive comment is:\n");
  322. X      for (i = 0; i < zoo_header->acmt_len; i++) {/* show it */
  323. X         ch = zgetc (zoo_file) & 0x7f;          /* 7 bits only */
  324. X         if (newline)
  325. X            printf (">> ");        /* indent and mark comment lines thus */
  326. X         zputchar (ch);
  327. X         if (ch == '\n')
  328. X            newline = 1;
  329. X         else
  330. X            newline = 0;
  331. X      }
  332. X      if (!newline)              /* always terminate with newline */
  333. X         zputchar ('\n');
  334. X   }
  335. X} /* show_acmt() */
  336. END_OF_FILE
  337. if test 9637 -ne `wc -c <'comment.c'`; then
  338.     echo shar: \"'comment.c'\" unpacked with wrong size!
  339. fi
  340. # end of 'comment.c'
  341. fi
  342. if test -f 'misc.c' -a "${1}" != "-c" ; then 
  343.   echo shar: Will not clobber existing file \"'misc.c'\"
  344. else
  345. echo shar: Extracting \"'misc.c'\" \(9670 characters\)
  346. sed "s/^X//" >'misc.c' <<'END_OF_FILE'
  347. X#ifndef LINT
  348. X/* @(#) misc.c 2.6 88/08/15 16:17:23 */
  349. Xstatic char sccsid[]="@(#) misc.c 2.6 88/08/15 16:17:23";
  350. X#endif /* LINT */
  351. X
  352. X/*
  353. XCopyright (C) 1986, 1987 Rahul Dhesi -- All rights reserved
  354. X(C) Copyright 1988 Rahul Dhesi -- All rights reserved
  355. X*/
  356. X#include "options.h"
  357. X/* Miscellaneous functions needed by Zoo but not by Ooz */
  358. X
  359. X#include "zoo.h"
  360. X#include "zooio.h"
  361. X#include "various.h"
  362. X
  363. X#include "errors.i"
  364. X#include "zoofns.h"
  365. X#ifndef NOSIGNAL
  366. X#include <signal.h>
  367. X#endif
  368. X
  369. X#ifdef NEEDCTYP
  370. X#include <ctype.h>
  371. X#else
  372. X#include "portable.h"
  373. X#endif
  374. X
  375. X#ifdef LINT_ARGS
  376. Xint ver_too_high (struct zoo_header *);
  377. X#else
  378. Xint ver_too_high ();
  379. X#endif
  380. X
  381. X
  382. X/*
  383. Xcalc_ofs() is given a string that (supposedly) begins with a string
  384. Xof digits.  It returns a corresponding numeric value.  If no such
  385. Xstring, it aborts the program with a fatal error message.
  386. X*/
  387. Xlong calc_ofs(str)
  388. Xchar *str;
  389. X{
  390. X   long retval;
  391. X   char *p;
  392. X   retval = 0L;
  393. X   p = str; /* save for error message */
  394. X   while (isdigit(*str)) {
  395. X      retval = retval * 10L + (*str-'0');
  396. X      str++;
  397. X   }
  398. X   if (*str != '\0')
  399. X      prterror ('f', "Invalid number %s\n", p);
  400. X   return (retval);
  401. X}
  402. X
  403. X/*
  404. Xchoosefname() decides which filename to use.  If a long filename is present,
  405. Xand if the syntax is that of UNIX, MS-DOS or the portable form, we use it;
  406. Xelse we use the short filename. 
  407. X*/
  408. X
  409. Xchar *choosefname(direntry)
  410. Xstruct direntry *direntry;
  411. X{
  412. X   char *retptr;                 /* pointer to name that we will return */
  413. X   switch (direntry->system_id) {
  414. X      case SYSID_NIX:
  415. X      case SYSID_PORTABLE:
  416. X      case SYSID_MS:
  417. X         retptr = (direntry->namlen != 0) ? direntry->lfname : direntry->fname;
  418. X         break;
  419. X      default:
  420. X         retptr = direntry->fname;
  421. X         break;
  422. X   }
  423. X   return (retptr);
  424. X} /* choosefname() */
  425. X
  426. X/* 
  427. Xcombine() combines a directory name and a filename, making sure the
  428. Xtwo are separated by a path separator 
  429. X*/
  430. Xchar *combine(result, dirname, fname)
  431. Xchar result[], *dirname, *fname;
  432. X{
  433. X   *result = '\0';
  434. X   if (*dirname != '\0') {
  435. X#ifdef DIR_LBRACK /* hack for VMS */
  436. X      strcat (result, DIR_LBRACK);
  437. X
  438. X      /*  "/" => "[",  "./" => "[."  others => "[." */
  439. X
  440. X      if (dirname[0] == '/') {        /* absolute path => "[" */
  441. X         strcat (result, dirname + 1);
  442. X      } else if (dirname[0] == '.' && dirname[1] == '/') {
  443. X         strcat (result, CUR_DIR);
  444. X         strcat (result, dirname + 2);
  445. X      } else {
  446. X         strcat (result, CUR_DIR);
  447. X         strcat (result, dirname);
  448. X      }
  449. X
  450. X/* folowing #ifdef block ought to be outside #ifdef DIR_LBRACK, and
  451. X   for loop should then start with p=result.  This is currently
  452. X   just a hack for VMS.
  453. X*/
  454. X#ifdef DIR_SEP
  455. X   if (DIR_SEP != '/') {   /* if char separating dirs is not "/",  */
  456. X      char *p;
  457. X      for (p = result+2;  *p != '\0';  p++) /* change it to underscore */
  458. X        if (*p == DIR_SEP)
  459. X           *p = '_';
  460. X   }
  461. X#endif
  462. X
  463. X      {
  464. X         char *p;
  465. X         for (p = result; *p != '\0';  p++)
  466. X         if (*p == '/')
  467. X            *p = '.';
  468. X      }
  469. X#else
  470. X      strcat (result, dirname);
  471. X#endif
  472. X      if (*lastptr(result) != *PATH_CH)
  473. X         strcat(result, PATH_CH);
  474. X   }
  475. X
  476. X   strcat(result, fname);
  477. X   return (result);
  478. X}
  479. X
  480. X/*
  481. Xfullpath() accepts a pointer to a directory entry and returns the
  482. Xcombined directory name + filename.  The long filename is used
  483. Xif available, else the short filename is used.
  484. X*/
  485. Xchar *fullpath (direntry)
  486. Xstruct direntry *direntry;
  487. X{
  488. X    static char result[PATHSIZE];
  489. X    combine (result,
  490. X                direntry->dirlen != 0 ? direntry->dirname : "", 
  491. X                (direntry->namlen != 0) ? direntry->lfname : direntry->fname
  492. X              );
  493. X    return (result);
  494. X}
  495. X
  496. X/* 
  497. Xver_too_high returns true if version of provided archive header is
  498. Xtoo high for us to manipulate archive
  499. X*/
  500. X
  501. Xint ver_too_high (header)
  502. Xstruct zoo_header *header;
  503. X{
  504. X   return (header->major_ver > MAJOR_VER ||
  505. X            (header->major_ver == MAJOR_VER &&
  506. X             header->minor_ver > MINOR_VER));
  507. X}
  508. X
  509. X/* 
  510. Xrwheader() reads archive header, checks consistency, makes sure its
  511. Xversion number is not too high, updates it if too low, and seeks to
  512. Xbeginning of first directory entr.  If `preserve' is 1, it preserves
  513. Xthe header type;  if `preserve' is 0, it gives a fatal error message
  514. Xif type is 0.
  515. X*/
  516. X
  517. Xvoid rwheader (header, zoo_file, preserve)
  518. Xregister struct zoo_header *header;
  519. XZOOFILE zoo_file;
  520. Xint preserve;
  521. X{
  522. X
  523. X   frd_zooh (header, zoo_file);
  524. X
  525. X   if ((header->zoo_start + header->zoo_minus) != 0L)
  526. X      prterror ('f', failed_consistency);
  527. X   if (ver_too_high (header))
  528. X      prterror ('f', wrong_version, header->major_ver, header->minor_ver);
  529. X
  530. X    if (preserve == 0 && header->type == 0)
  531. X        prterror ('f', packfirst);
  532. X
  533. X   /* We reach here if the archive version is not too high.  Now, if it
  534. X   isn't the same as ours, we bring it up to ours so the modified archive
  535. X   will be safe from previous versions of Zoo */
  536. X
  537. X   if (header->major_ver != MAJOR_VER || header->minor_ver != MINOR_VER) {
  538. X      header->major_ver = MAJOR_VER;
  539. X      header->minor_ver = MINOR_VER;
  540. X      zooseek (zoo_file, 0L, 0);            /* seek to beginning */
  541. X      fwr_zooh (header, zoo_file);
  542. X   }
  543. X   zooseek (zoo_file, header->zoo_start, 0); /* seek to where data begins */
  544. X} /* rwheader */
  545. X
  546. X/*
  547. Xwritedir() write a directory entry with keyboard interrupt disabled
  548. X*/
  549. Xvoid writedir (direntry, zoo_file)
  550. Xstruct direntry *direntry;
  551. XZOOFILE zoo_file;
  552. X{
  553. X#ifndef NOSIGNAL  
  554. X   int (*oldsignal)();
  555. X   oldsignal = signal (SIGINT, SIG_IGN);
  556. X#endif
  557. X   if (fwr_dir (direntry, zoo_file) == -1)
  558. X      prterror ('f', disk_full);
  559. X#ifndef NOSIGNAL
  560. X   signal (SIGINT, oldsignal);
  561. X#endif
  562. X}
  563. X
  564. X/* 
  565. Xreaddir() reads a directory entry from an archive.  If the directory
  566. Xentry is invalid and if fail is 1, it causes a fatal error;
  567. Xelse it returns.  Return value is 0 if no error else -1;
  568. X*/
  569. X
  570. Xint readdir (direntry, zoo_file, fail)    /* read directory entry */
  571. Xregister struct direntry *direntry;
  572. XZOOFILE zoo_file;
  573. Xint fail;                              /* 0 -> return, 1 -> abort on error */
  574. X{
  575. X   if (frd_dir (direntry, zoo_file) < 0) {
  576. X      if (fail) {
  577. X         prterror ('f', bad_directory);
  578. X      } else
  579. X         return (-1);
  580. X   }
  581. X   if (direntry->zoo_tag != ZOO_TAG) {
  582. X      if (fail)
  583. X         prterror ('f', bad_directory);
  584. X      else
  585. X         return (-1);
  586. X   }
  587. X   return (0);
  588. X}
  589. X
  590. X/* use pointer version below */
  591. X#ifdef COMMENT
  592. X/* instr() searches a string for a substring */
  593. Xinstr (s, t)      /* return index of string t in string s, -1 if none */
  594. Xchar s[], t[];    /*  .. from K&R page 67 */
  595. X{
  596. X   int i;
  597. X   register int j, k;
  598. X   for (i = 0; s[i] != '\0'; i++) {
  599. X      for (j = i, k = 0; t[k] != '\0' && s[j]==t[k]; j++, k++)
  600. X         ;
  601. X      if (t[k] == '\0')
  602. X         return (i);
  603. X   }
  604. X   return (-1);
  605. X}
  606. X#endif COMMENT
  607. X
  608. X/* instr() searches a string for a substring */
  609. X/* from J. Brian Waters */
  610. Xint instr (s, t)           /* return the position of t in s, -1 if none */
  611. Xchar *s, *t;                /*  a pointer version of K&R index function p.67 */
  612. X{               /* renamed to instr() to avoid conflicts with C RTL - JBW */
  613. X
  614. X   register char *i, *j, *k;
  615. X
  616. X   for (i = s; *i; i++) {
  617. X      for (j = i, k = t; (*k) && (*j++ == *k); k++)
  618. X         ;
  619. X       if (!*k)
  620. X         return ((int) (i - s));
  621. X   }
  622. X   return(-1);
  623. X}
  624. X
  625. X/* cfactor() calculates the compression factor given a directory entry */
  626. Xint cfactor (org_size, size_now)
  627. Xlong org_size, size_now;
  628. X{
  629. X   register int size_factor;
  630. X   if ((unsigned long) org_size > 1000000) { /* avoid later overflow */
  631. X      org_size = (unsigned long) org_size / 1024;
  632. X      size_now = (unsigned long) size_now / 1024;
  633. X   }
  634. X   if (org_size == 0)         /* avoid division by zero */
  635. X      size_factor = 0;
  636. X   else {
  637. X      size_factor = (int)
  638. X         (
  639. X            (1000 * 
  640. X               ((unsigned long) org_size - (unsigned long) size_now)
  641. X            ) / org_size + 5
  642. X         ) / 10;
  643. X   }
  644. X   return (size_factor);
  645. X}
  646. X
  647. X#ifndef STRDUP
  648. X/***********
  649. Xstrdup() duplicates a string using dynamic memory.
  650. X*/
  651. X
  652. Xchar *strdup (str)
  653. Xregister char *str;
  654. X{
  655. X   return (strcpy (emalloc (strlen(str)+1), str));
  656. X}
  657. X#endif /* STRDUP */
  658. X
  659. X/**************
  660. Xcmpnum() compares two pairs of unsigned integers and returns a negative,
  661. Xzero, or positive value as the comparison yields less than, equal, or
  662. Xgreater than result.  Each pair of unsigned integers is considered to be the
  663. Xmore significant and the less significant half of a longer unsigned number.
  664. X
  665. XNote:  cmpnum is used to compare dates and times.
  666. X*/
  667. X
  668. Xint cmpnum (hi1, lo1, hi2, lo2)
  669. Xregister unsigned int hi1, hi2;
  670. Xunsigned int lo1, lo2;
  671. X{
  672. X   if (hi1 != hi2)
  673. X      return (hi1 > hi2 ? 1 : -1);
  674. X   else {
  675. X        if (lo1 == lo2)
  676. X            return (0);
  677. X        else
  678. X            return (lo1 > lo2 ? 1 : -1);
  679. X    }
  680. X}
  681. X
  682. X/*******************/
  683. X/* writenull() */
  684. X/* writes a null directory entry to an open archive */
  685. Xvoid writenull (file, length)
  686. XZOOFILE file;
  687. Xint length;
  688. X{
  689. X#ifndef NOSIGNAL
  690. X   int (*oldsignal)();
  691. X#endif
  692. X   struct direntry newentry;
  693. X   memset ((char *) &newentry, 0, sizeof (newentry));
  694. X   newentry.zoo_tag = ZOO_TAG;
  695. X   newentry.type = 2;
  696. X   /* Force entry to be the required length plus possibly 2 stray bytes
  697. X   by dividing up the needed padding into dirlen and namlen. */
  698. X   if (length > SIZ_DIRL)
  699. X      newentry.dirlen = newentry.namlen = (length-SIZ_DIRL)/2 + 2;
  700. X   else
  701. X      newentry.dirlen = newentry.namlen = 0;
  702. X#ifndef NOSIGNAL
  703. X   oldsignal = signal (SIGINT, SIG_IGN);
  704. X#endif
  705. X   if (fwr_dir (&newentry, file) == -1)
  706. X      prterror ('f', disk_full);
  707. X#ifndef NOSIGNAL
  708. X   signal (SIGINT, oldsignal);
  709. X#endif
  710. X}
  711. X
  712. X#ifdef FORCESLASH
  713. X/*******************/
  714. X/*
  715. Xfixslash() changes all "\" characters in the supplied string to "/".
  716. X*/
  717. X
  718. Xvoid fixslash (str)
  719. Xchar *str;
  720. X{
  721. X   register char *p;
  722. X   for (p = str; *p != '\0'; p++)
  723. X      if (*p == '\\')
  724. X         *p = '/';
  725. X}
  726. X#endif /* FORCESLASH */
  727. END_OF_FILE
  728. if test 9670 -ne `wc -c <'misc.c'`; then
  729.     echo shar: \"'misc.c'\" unpacked with wrong size!
  730. fi
  731. # end of 'misc.c'
  732. fi
  733. if test -f 'vms.c' -a "${1}" != "-c" ; then 
  734.   echo shar: Will not clobber existing file \"'vms.c'\"
  735. else
  736. echo shar: Extracting \"'vms.c'\" \(9468 characters\)
  737. sed "s/^X//" >'vms.c' <<'END_OF_FILE'
  738. X#ifndef LINT
  739. X/* @(#) vms.c 1.4 87/07/26 22:48:45 */
  740. X/* @(#) vms.c 2.2 88/01/09 03:47:52 */
  741. X#endif /* LINT */
  742. X
  743. X/* machine.c for VMS */
  744. X
  745. X/****************
  746. XDate and time functions are standard UNIX-style functions, except that
  747. XVAX/VMS does not know about timezones.  "nixtime.i" will be included 
  748. Xby machine.c.
  749. X*/
  750. X
  751. X#include <stat.h>
  752. X#include <time.h>
  753. X
  754. X/* Function isuadir() returns 1 if the supplied filename is a directory, 
  755. Xelse it returns 0.  
  756. X*/
  757. X
  758. Xint isuadir (file)
  759. Xchar *file;
  760. X{
  761. X   struct stat buf;           /* buffer to hold file information */
  762. X   if (stat (file, &buf) == -1) {
  763. X      return (0);             /* inaccessible -- assume not dir */
  764. X   } else {
  765. X      if (buf.st_mode & S_IFDIR)
  766. X         return (1);
  767. X      else
  768. X         return (0);
  769. X   }
  770. X}
  771. X
  772. X/****************
  773. XFunction fixfname() converts the supplied filename to a syntax
  774. Xlegal for the host system.  It is used during extraction.  We
  775. Xallow a maximum of one dot in the filename, and it must not
  776. Xbe at the beginning.  We also truncate the number of charac-
  777. Xters preceding and following the dot to at most 39.
  778. X*/
  779. X
  780. Xchar *strchr();
  781. X
  782. Xchar *fixfname(fname)
  783. Xchar *fname;
  784. X{
  785. X   char *p;
  786. X   char *dotpos;
  787. X   static char legal[] = 
  788. X      "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_.0123456789";
  789. X
  790. X   /* convert all characters to legal characters */
  791. X   for (p = fname;  *p != '\0';  p++)
  792. X      if (strchr (legal, *p) == 0) {
  793. X         if (*p == '-' || *p == ' ')
  794. X            *p = '_';
  795. X         else
  796. X            *p = legal [ *p % 26 ];
  797. X      }
  798. X
  799. X   /* first char can't be dot */
  800. X   if (*fname == '.')
  801. X      *fname = 'X';
  802. X
  803. X   /* find embedded dot if any */
  804. X   dotpos = strchr (fname, '.');
  805. X
  806. X   if (dotpos != NULL) {
  807. X      for (p = dotpos+1;  *p != '\0';  p++)  /* remove 2nd dot onwards */
  808. X         if (*p == '.')
  809. X            *p = '_';
  810. X      if (dotpos - fname + 1 > 39) {  /* more than 39 before dot not allowed */
  811. X         char *q;
  812. X         p = fname + 39;
  813. X         q = dotpos;
  814. X         while (*p++ = *q++)  /* the notational convenience is considerable */
  815. X            ;
  816. X         dotpos = strchr (fname, '.');
  817. X      }
  818. X      if (strlen (dotpos + 1) > 39)  /* more than 39 after dot not allowed */
  819. X         *(dotpos + 39 + 1) = '\0';
  820. X   } else
  821. X      *(fname + 39) = '\0'; /* no dots, just truncate to 39 characters */
  822. X   return (fname);
  823. X}
  824. X
  825. X/*
  826. XFunction gettz(), returns the offset from GMT in seconds of the
  827. Xlocal time, taking into account daylight savings time -- or it
  828. Xwould, if VAX/VMS knew about timezones!  It's just a no-op.
  829. X*/
  830. Xlong gettz()
  831. X{
  832. X   return 0L;
  833. X}
  834. X
  835. X/* Standard UNIX-compatible time functions */
  836. X#include "nixtime.i"
  837. X
  838. X/*
  839. XFunction utime() is just a stub.  VMS C doesn't have it or
  840. Xan equivalent.
  841. X*/
  842. Xint utime (fname) char *fname; {}
  843. X
  844. X/*
  845. XFunction unlink() will delete a file using the VMS C delete()
  846. Xfunction.
  847. X*/
  848. Xint unlink (fname)
  849. Xchar *fname;
  850. X{
  851. X   return (delete (fname));
  852. X}
  853. X
  854. X/*
  855. XFunction zooexit() receives attempts at exit.  It always invokes
  856. Xexit() with status=1.
  857. X*/
  858. Xint zooexit (status)
  859. Xint status;
  860. X{
  861. X   exit (1);
  862. X}
  863. X
  864. X
  865. X/*
  866. XFunction rename() renames a file.  
  867. XThanks to Owen Anthony <bsu-cs!anthony>.
  868. X*/
  869. X
  870. X#include <descrip.h>
  871. X
  872. X#ifndef VMS_RENAME /* if not using VMS 4.6 library rename() */
  873. Xint rename (new_name, old_name)
  874. Xchar *new_name, *old_name;
  875. X{
  876. X   int status;
  877. X   struct dsc$descriptor_s file1, file2;
  878. X   file1.dsc$w_length = strlen (old_name);  /* descriptor for old name */
  879. X   file1.dsc$a_pointer = old_name;
  880. X   file1.dsc$b_class = DSC$K_CLASS_S;
  881. X   file1.dsc$b_dtype = DSC$K_DTYPE_T;
  882. X   file2.dsc$w_length = strlen (new_name);  /* descriptor for new name */
  883. X   file2.dsc$a_pointer = new_name;
  884. X   file2.dsc$b_class = DSC$K_CLASS_S;
  885. X   file2.dsc$b_dtype = DSC$K_DTYPE_T;
  886. X
  887. X   status = LIB$RENAME_FILE (&file1, &file2);
  888. X
  889. X   return ((status & ~1) == 1);
  890. X}
  891. X#endif /* VMS_RENAME */
  892. X
  893. X/*
  894. XFunction specfname() modifies filenames before they are stored
  895. Xin an archive.  Currently we remove any trailing version field,
  896. Xand then any trailing dot.
  897. X*/
  898. Xchar *specfname (fname)
  899. Xchar *fname;
  900. X{
  901. X   char *p;
  902. X   p = strchr (fname, ';');
  903. X   if (p != NULL)
  904. X      *p = '\0';
  905. X   if (*fname != '\0') {
  906. X      p = fname + strlen (fname) - 1; /* point to last char */
  907. X      if (*p == '.')                  /* remove any trailing dot */
  908. X         *p = '\0';
  909. X   }
  910. X   return (fname);
  911. X}
  912. X
  913. X/* 
  914. XFunction specdir() modifies directory names before they are stored
  915. Xin an archive.  We remove any leading device name or logical
  916. Xname and and the [ and ] that bracket any directory name.
  917. XThen we change any dots in the directory name to slashes.
  918. X*/
  919. X
  920. X#if 0
  921. X/* test stub that just truncates dir to null string */
  922. Xchar *specdir (fname) char *fname;
  923. X{ *fname = '\0'; return (fname); }
  924. X#else
  925. X
  926. Xchar *specdir (fname)
  927. Xchar *fname;
  928. X{
  929. X   char *p;
  930. X   char tmpstr[LFNAMESIZE];
  931. X
  932. X   p = strchr (fname, ':');      /* remove chars upto and including : */
  933. X   if (p != NULL) {
  934. X      strcpy (tmpstr, p+1);
  935. X      strcpy (fname, tmpstr);
  936. X   }
  937. X
  938. X   p = strchr (fname, '[');      /* remove chars upto and including [ */
  939. X   if (p != NULL) {
  940. X      strcpy (tmpstr, p+1);
  941. X      strcpy (fname, tmpstr);
  942. X   }
  943. X
  944. X   p = strchr (fname, ']');      /* truncate at ] */
  945. X   if (p != NULL) {
  946. X      if (*(p+1) != '\0')
  947. X         prterror ('w', "Trailing garbage in directory name\n");
  948. X      *p = '\0';
  949. X   }
  950. X
  951. X   for (p = fname;  *p != '\0';  p++)   /* change dots to slashes */
  952. X      if (*p == '.')
  953. X         *p = '/';
  954. X
  955. X   /* make sure there is a leading slash -- just a hack for now */
  956. X   if (*fname != '/') {
  957. X      strcpy (tmpstr, fname);
  958. X      strcpy (fname, "/");
  959. X      strcat (fname, tmpstr);
  960. X   }
  961. X
  962. X#ifdef DEBUG
  963. Xprintf ("dir name transformed to \"%s\"\n", fname);
  964. X#endif
  965. X}
  966. X#endif
  967. X
  968. X#define  FMAX  3        /* Number of different filename patterns */
  969. X
  970. Xchar *nextfile (what, filespec, fileset)
  971. Xint what;                        /* whether to initialize or match      */
  972. Xregister char *filespec;         /* filespec to match if initializing   */
  973. Xregister int fileset;            /* which set of files                  */
  974. X{
  975. X   int status;
  976. X   char *p;                      /* temp ptr */
  977. X   struct dsc$descriptor_s d_fwild, d_ffound;
  978. X   static int first_time [FMAX+1];
  979. X   static char saved_fspec [FMAX+1][PATHSIZE];  /* our own copy of filespec */
  980. X   static char found_fspec [FMAX+1][PATHSIZE];  /* matched filename */
  981. X   static unsigned long context [FMAX+1];    /* needed by VMS */
  982. X   if (what == 0) {
  983. X      strcpy (saved_fspec[fileset], filespec);  /* save the filespec */
  984. X      first_time[fileset] = 1;
  985. X      return (0);
  986. X   }
  987. X
  988. X   /* Reach here if what is not 0, so it must be 1 */
  989. X
  990. X   /* Create a descriptor for the wildcarded filespec */
  991. X   d_fwild.dsc$w_length = strlen (saved_fspec[fileset]);
  992. X   d_fwild.dsc$a_pointer = saved_fspec[fileset];
  993. X   d_fwild.dsc$b_class = DSC$K_CLASS_S;
  994. X   d_fwild.dsc$b_dtype = DSC$K_DTYPE_T;
  995. X
  996. X   d_ffound.dsc$w_length = sizeof (found_fspec[fileset]);
  997. X   d_ffound.dsc$a_pointer = found_fspec[fileset];
  998. X   d_ffound.dsc$b_class = DSC$K_CLASS_S;
  999. X   d_ffound.dsc$b_dtype = DSC$K_DTYPE_T;
  1000. X
  1001. X   if (first_time[fileset]) {
  1002. X      first_time[fileset] = 0;
  1003. X      context[fileset] = 0L;   /* tell VMS this is first search */
  1004. X   }
  1005. X   status = LIB$FIND_FILE (&d_fwild, &d_ffound, &context[fileset]);
  1006. X   status = status & 1;    /* use only lowest bit */
  1007. X
  1008. X   if (status == 0) {
  1009. X      LIB$FIND_FILE_END (&context[fileset]);
  1010. X      return ((char *) 0);
  1011. X   } else {
  1012. X      found_fspec[fileset][d_ffound.dsc$w_length] = '\0'; /* just in case */
  1013. X      p = found_fspec[fileset];
  1014. X      while (*p != ' ' && *p != '\0')
  1015. X         p++;
  1016. X      if (*p != '\0')
  1017. X         *p = '\0';
  1018. X      return (found_fspec[fileset]);
  1019. X   }
  1020. X}
  1021. X
  1022. X/*
  1023. XFunction vmsmkdir() converts the received directory name into VMS
  1024. Xformat and then creates a directory.
  1025. X*/
  1026. Xint vmsmkdir (subdir)
  1027. Xchar *subdir;
  1028. X{
  1029. X   char *lastptr();
  1030. X   char *p;
  1031. X   char tmp[LFNAMESIZE];
  1032. X
  1033. X   p = subdir;
  1034. X
  1035. X   /* leading "/" => "[", otherwise => "[." */
  1036. X   if (*p == '/') {
  1037. X      strcpy (tmp, "[");
  1038. X      p++;
  1039. X   } else {
  1040. X      strcpy (tmp, "[.");
  1041. X      while (*p == '/' || *p == '.')
  1042. X         p++;
  1043. X   }
  1044. X
  1045. X   strcat (tmp, p);
  1046. X
  1047. X   /* 
  1048. X   VMS doesn't like dots in directory names, so we convert them to
  1049. X   underscores.  Leave first two characters untouched, because
  1050. X   we don't want to corrupt a leading "[." into "[_".
  1051. X   */
  1052. X   for (p = tmp + 2;  *p != '\0';  p++)
  1053. X      if (*p == '.')
  1054. X         *p = '_';
  1055. X
  1056. X   /* convert all slashes to dots */
  1057. X   for (p = tmp; *p != '\0';  p++)
  1058. X      if (*p == '/')
  1059. X         *p = '.';
  1060. X
  1061. X   /* Remove any trailing dot */
  1062. X   p = lastptr (tmp);
  1063. X   if (*p == '.')
  1064. X      *p = '\0';
  1065. X
  1066. X   /* append closing bracket */
  1067. X   strcat (tmp, "]");
  1068. X#if 0
  1069. X   printf ("\nmaking directory \"%s\"\n", tmp);
  1070. X#endif
  1071. X   return (mkdir (tmp, 0));
  1072. X}
  1073. X
  1074. X/*
  1075. XFunction spec_wild() transforms a pattern supplied on the command line into one
  1076. Xsuitable for wildcard expansion in the most efficient way possible.  We change
  1077. Xeach "?" to "%" but let "*" remain unchanged.  We also append a ".*" if the
  1078. Xpattern contains no dot, so "*" will be interpreted as "*.*" for VMS globbing. 
  1079. X*/
  1080. Xchar *spec_wild (arg)
  1081. Xchar *arg;
  1082. X{
  1083. X   char *p;
  1084. X#ifdef DEBUG
  1085. X   printf ("spec_wild: arg = [%s]\n", arg);
  1086. X#endif
  1087. X   if (*lastptr (arg) == ']')      /* add *.* if no filename */
  1088. X      strcat (arg, "*.*");
  1089. X   p = nameptr (arg);              /* point p to filename part */
  1090. X
  1091. X   /* if no dot in name append ".*" */
  1092. X   if (strchr (p, '.') == NULL)
  1093. X      strcat (p, ".*");
  1094. X
  1095. X   for ( ; *p != '\0';  p++)        /* change every "?" to "%" */
  1096. X      if (*p == '?')
  1097. X         *p = '%';
  1098. X#ifdef DEBUG
  1099. X   printf ("spec_wild: arg changed to [%s]\n", arg);
  1100. X#endif
  1101. X   return (arg);
  1102. X}
  1103. END_OF_FILE
  1104. if test 9468 -ne `wc -c <'vms.c'`; then
  1105.     echo shar: \"'vms.c'\" unpacked with wrong size!
  1106. fi
  1107. # end of 'vms.c'
  1108. fi
  1109. if test -f 'zoo.c' -a "${1}" != "-c" ; then 
  1110.   echo shar: Will not clobber existing file \"'zoo.c'\"
  1111. else
  1112. echo shar: Extracting \"'zoo.c'\" \(9863 characters\)
  1113. sed "s/^X//" >'zoo.c' <<'END_OF_FILE'
  1114. X#ifndef LINT
  1115. X/* @(#) zoo.c 2.24 88/01/29 00:55:09 */
  1116. Xstatic char sccsid[]="@(#) zoo.c 2.24 88/01/29 00:55:09";
  1117. X#endif /* LINT */
  1118. X
  1119. X#if 0
  1120. X#define TRACEI(item)    printf("line %d: %s= %d\n", __LINE__, #item, item)
  1121. X#define TRACES(item)    printf("line %d: %s= [%s]\n", __LINE__, #item, item)
  1122. X#endif
  1123. X
  1124. Xextern char version[];
  1125. X
  1126. X/*
  1127. XCopyright (C) 1986, 1987 Rahul Dhesi -- All rights reserved
  1128. X(C) Copyright 1988 Rahul Dhesi -- All rights reserved
  1129. X*/
  1130. X#include "options.h"
  1131. X#include "zooio.h"
  1132. X#include "various.h"
  1133. X
  1134. X#include "zoo.h"
  1135. X#include "zoofns.h"
  1136. X
  1137. X#include "errors.i"
  1138. X#include "zoomem.h"
  1139. X
  1140. X#ifdef TRACE_IO
  1141. Xint verbose = 0;
  1142. X#endif
  1143. X
  1144. X#ifdef LINT_ARGS
  1145. Xint instr (char *, char *);
  1146. X#else
  1147. Xint instr ();
  1148. X#endif
  1149. X
  1150. Xchar *out_buf_adr;      /* points to memory allocated for output buffer(s) */
  1151. Xchar *in_buf_adr;       /* points to memory allocated for input buffer */
  1152. X
  1153. X/* static declarations */
  1154. Xint quiet = 0;             /* whether to be quiet */
  1155. Xint next_arg = FIRST_ARG; /* filenames start at this position */
  1156. Xint arg_count;          /* count of arguments supplied to program */
  1157. Xchar **arg_vector;      /* vector of arguments supplied to program */
  1158. X
  1159. Xmain(argc,argv)
  1160. Xregister int argc;
  1161. Xregister char **argv;
  1162. X{
  1163. X   char *zooname;          /* synonym for argv[2] -- to make life easier */
  1164. X#ifndef OOZ
  1165. X   static char incorrect_args[] = "Incorrect number of arguments.\n";
  1166. X   int filecount;          /* how many filespecs supplied */
  1167. X#endif /* OOZ */
  1168. X
  1169. X#ifdef OOZ
  1170. X#else
  1171. X/* else not OOZ */
  1172. X      static char usage[] = "Usage: zoo {acDeglLPTuUvx}[aAcCdEfInmMNoOpPqu1:/.@n] archive file\n(\"zoo h\" for help)\n";
  1173. X      static char nov_usage[] =
  1174. X          "\nNovice usage:  zoo -cmd archive[.zoo] file...  where -cmd is one of these:\n";
  1175. X      char *option;
  1176. X
  1177. X      static char nov_cmds[] =
  1178. X         /* ADD=0EXT=5    MOV=14TES=20PRI=26 DEL=33  LIS=41UPD=47  FRE=55   COMMENT=64 */
  1179. X           "-add -extract -move -test -print -delete -list -update -freshen -comment\n";
  1180. X
  1181. X#ifdef NOENUM
  1182. X#define NONE   -1
  1183. X#define ADD    0
  1184. X#define EXTRACT 5
  1185. X#define MOVE   14
  1186. X#define TEST   20
  1187. X#define PRINT  26
  1188. X#define DELETE 33
  1189. X#define LIST   41
  1190. X#define UPDATE 47
  1191. X#define FRESHEN   55
  1192. X#define COMMENT   64
  1193. X
  1194. Xint cmd = NONE;
  1195. X
  1196. X#else
  1197. X   enum choice {
  1198. X      NONE=-1, ADD=0, EXTRACT=5, MOVE=14, TEST=20, PRINT=26,
  1199. X      DELETE=33, LIST=41, UPDATE=47, FRESHEN=55, COMMENT=64
  1200. X   };
  1201. X   enum choice cmd = NONE;          /* assume no Novice command */
  1202. X#endif
  1203. X
  1204. X#endif /* end of not OOZ */
  1205. X
  1206. X#ifdef SPECINIT
  1207. X    void spec_init PARMS ((NOTHING));
  1208. X    spec_init();                            /* system-specific startup code */
  1209. X#endif
  1210. X
  1211. X   arg_count = argc;
  1212. X   arg_vector = argv;
  1213. X   zooname = argv[FIRST_ARG-1];     /* points to name or archive */
  1214. X
  1215. X#ifdef OOZ
  1216. X   if (argc < 2) {
  1217. X      putstr (usage1);
  1218. X      putstr (usage2);
  1219. X      zooexit (1);
  1220. X   }
  1221. X#else
  1222. X/* else not OOZ */
  1223. X   if (argc < 2)
  1224. X      goto show_usage;
  1225. X   filecount = argc - 3;
  1226. X   option = strdup(argv[1]);
  1227. X
  1228. X#ifdef TRACE_IO
  1229. X   if (*option == ':') {         /* for debugging output */
  1230. X      verbose++;
  1231. X      option++;                  /* hide the : from other functions */
  1232. X   }
  1233. X#endif
  1234. X
  1235. X#ifdef WAIT_PROMPT
  1236. X   if (*option == 'w') {
  1237. X        option++;                        /* hide w from other functions */
  1238. X        printf ("Hit RETURN when ready: ");
  1239. X        while (getchar() != '\n')
  1240. X            ;
  1241. X    }
  1242. X#endif /* WAIT_PROMPT */
  1243. X
  1244. X   if (*option == 'h' || *option == 'H')
  1245. X      goto bigusage;
  1246. X    if (strchr("-acDegflLPTuUvVx", *option) == NULL)
  1247. X        goto give_list;
  1248. X
  1249. X   if (*option == '-') {
  1250. X
  1251. X#ifdef NOENUM
  1252. X      cmd = instr (nov_cmds, strlwr(option));
  1253. X#else
  1254. X      cmd = (enum choice) instr (nov_cmds, strlwr(option));
  1255. X#endif
  1256. X
  1257. X      if (strlen(option) < 2 || cmd == NONE)
  1258. X         goto show_usage;
  1259. X      if (  ((cmd == ADD || cmd == MOVE || cmd == FRESHEN ||
  1260. X                  cmd == UPDATE || cmd == DELETE) && argc < 4) ||
  1261. X            ((cmd == EXTRACT || cmd == TEST || cmd == LIST ||
  1262. X                     cmd == PRINT || cmd == COMMENT) && argc < 3)) {
  1263. X         fprintf (stderr, incorrect_args);
  1264. X         goto show_usage;
  1265. X      }
  1266. X   } else {
  1267. X        char *wheresI;        /* will be null if I option not supplied */
  1268. X        if    (
  1269. X                (
  1270. X                    strchr("au",*option) &&
  1271. X                    (
  1272. X                        (((wheresI = strchr(option,'I')) != 0) &&
  1273. X                            argc != 3) ||
  1274. X                        wheresI==NULL && argc < 4
  1275. X                    )
  1276. X                ) ||
  1277. X                 strchr("DU",*option) && argc < 4 ||
  1278. X             strchr("cexlvVL",*option) && argc < 3 ||
  1279. X             strchr("TP",*option)   && argc != 3 ||
  1280. X                 (*option == 'f' && argc != 2) ||
  1281. X                 (*option == 'g' &&
  1282. X                    (strchr(option,'A') == NULL && argc < 4 ||
  1283. X                     strchr(option,'A') != NULL && argc != 3
  1284. X                    )
  1285. X                 )
  1286. X            ) {
  1287. X         fprintf (stderr, incorrect_args);
  1288. X         goto show_usage;
  1289. X      }
  1290. X   }
  1291. X#endif /* end of not OOZ */
  1292. X
  1293. X#ifndef OOZ
  1294. X   /* if not doing a list and no extension in archive name, add default
  1295. X   extension */
  1296. X   if (*option != 'f' && cmd != LIST && strchr("lvVL", *option) == NULL &&
  1297. X         strchr(nameptr (zooname), EXT_CH) == NULL)
  1298. X      zooname = newcat (zooname, EXT_DFLT);
  1299. X#endif
  1300. X
  1301. X/*
  1302. XHere we allocate a large block of memory for the duration of the program.
  1303. Xlzc() and lzd() will use half of it each.  Routine getfile() will use all
  1304. Xof it.
  1305. X*/
  1306. X/* fudge factor to avoid off-by-one errors */
  1307. X#define  FUDGE    10
  1308. X
  1309. X/*                          fudge/2           fudge/2
  1310. X**             [______________||________________|]
  1311. X**               output buffer    input buffer
  1312. X*/
  1313. X   out_buf_adr = emalloc (OUT_BUF_SIZE + IN_BUF_SIZE + FUDGE);
  1314. X
  1315. X   /* input buffer is in top of allocated block */
  1316. X   in_buf_adr = out_buf_adr + OUT_BUF_SIZE + (FUDGE/2);
  1317. X
  1318. X#ifdef OOZ
  1319. Xzooext(zooname, "\0");     /* just extract -- no fancy stuff   */
  1320. Xzooexit (0);                  /* and exit normally                */
  1321. X#else
  1322. X/* else not OOZ -- parse command line and invoke a routine */
  1323. X   if (cmd != NONE) {
  1324. X      switch (cmd) {
  1325. X
  1326. X         case ADD:      zooadd (zooname, filecount, &argv[3], "aP:"); break;
  1327. X         case FRESHEN:  zooadd (zooname, filecount, &argv[3], "auP:"); break;
  1328. X         case UPDATE:   zooadd (zooname, filecount, &argv[3], "aunP:"); break;
  1329. X         case MOVE:     zooadd (zooname, filecount, &argv[3], "aMP:"); break;
  1330. X
  1331. X         case EXTRACT:  zooext (zooname, "x"); break;
  1332. X         case TEST:     zooext (zooname, "xNd"); break;
  1333. X         case PRINT:    zooext (zooname, "xp"); break;
  1334. X
  1335. X         case DELETE:   zoodel (zooname, "DP",1); break;
  1336. X         case LIST:     zoolist (&argv[2], "VC", argc-2); break;
  1337. X         case COMMENT:  comment (zooname, "c"); break;
  1338. X         default: goto show_usage;
  1339. X      }
  1340. X   } else
  1341. X      switch (*option) {
  1342. X
  1343. X         case 'a':
  1344. X         case 'u':
  1345. X         case 'T':   
  1346. X            zooadd (zooname, filecount, &argv[3], option); break;
  1347. X#ifdef FILTER
  1348. X            case 'f':
  1349. X                zoofilt (option);  break;
  1350. X#endif /* FILTER */
  1351. X         case 'D':
  1352. X            zoodel (zooname, option, 1); break;
  1353. X         case 'U':
  1354. X            zoodel (zooname, option, 0); break;
  1355. X            case 'g':
  1356. X                zoodel (zooname, option, 2); break;
  1357. X         case 'v':
  1358. X            case 'V':
  1359. X         case 'l': 
  1360. X            zoolist(&argv[2], option, 1); break;
  1361. X         case 'L': 
  1362. X            zoolist(&argv[2], option, argc-2); break;
  1363. X         case 'e':
  1364. X         case 'x': 
  1365. X            zooext(zooname, option); break;
  1366. X         case 'P':
  1367. X            zoopack (zooname, option); break;
  1368. X         case 'c':
  1369. X            comment (zooname, option); break;
  1370. X         default:
  1371. X            goto give_list;
  1372. X      }
  1373. Xzooexit (0);      /* don't fall through */
  1374. X
  1375. X/* usage list including Novice commands */
  1376. Xshow_usage:
  1377. X   fprintf (stderr, "%s%s%s", usage, nov_usage, nov_cmds); zooexit (1);
  1378. X
  1379. X/* brief usage list */
  1380. Xgive_list:
  1381. X    fprintf (stderr, usage); zooexit (1);
  1382. X
  1383. X/* help screen */
  1384. Xbigusage:
  1385. X
  1386. Xprintf ("Zoo archiver, %s\n", version);
  1387. Xprintf("(C) Copyright 1988 Rahul Dhesi -- Noncommercial use permitted\n");
  1388. X
  1389. Xprintf (usage);
  1390. Xprintf ("\nChoose a command from within {} and zero or more modifiers from within [].\n");
  1391. X
  1392. Xprintf ("E.g.:  `zoo a save /bin/*' will archive all files in /bin into save.zoo.\n");
  1393. Xprintf ("(Please see the user manual for a complete description of commands.)\n\n");
  1394. X
  1395. Xprintf (" Commands in {} mean:         |Modifiers in [] mean:\n");
  1396. X
  1397. Xprintf ("  a     add files             | a     show archive name(s) in listing\n");
  1398. Xprintf ("  c     update comments       | A     apply g or c to archive\n");
  1399. Xprintf ("  D     delete stored files   | c     add/list comments\n");
  1400. Xprintf ("  e,x   extract files         | d     extract/list deleted files too\n");
  1401. Xprintf ("  g     adj. gen. limit/count | dd    extract/list only deleted files\n");
  1402. Xprintf ("  l,L,v,V list filenames      | E     erase backup after packing\n");
  1403. Xprintf ("  P     pack archive          | f     fast add (no compression) or list\n");
  1404. Xprintf ("  T     fix archive datestamp | M     move when adding (erase original)\n");
  1405. Xprintf ("  u     add only newer files  | n     add only files not already in archive\n");
  1406. Xprintf ("  U     undelete stored files | N     send extracted data to Neverland\n");
  1407. X#ifdef FILTER
  1408. Xprintf ("  f     act as filter         | c/u   compress/uncompress as filter\n");
  1409. X#endif /* FILTER */
  1410. Xprintf (" -----------------------------  O     don't ask \"Overwrite?\"\n");
  1411. Xprintf ("  q     be quiet                p     pipe extracted data to standard output\n");
  1412. Xprintf ("  :     don't store dir names   /,//  extract full pathnames\n");
  1413. Xprintf ("  .     pack to current dir     I     add filenames read from stdin\n");
  1414. Xprintf ("  C     show file CRC value     +/-   enable/disable generations\n");
  1415. Xprintf ("  S     overwrite newer files   g     list generation limits\n");
  1416. Xprintf ("  P     pack after adding       @n    start extract/list at position n\n");
  1417. X
  1418. X#ifdef FATTR
  1419. Xprintf ("  m     list file modes         OO    overwrite read-only files\n");
  1420. X#endif /* FATTR */
  1421. X
  1422. Xprintf (nov_usage);
  1423. Xprintf (nov_cmds);
  1424. X#endif /* end of not OOZ */
  1425. X
  1426. X/* NOTE:  if allowed to fall through and return without an exit() statement,
  1427. X   it was printing garbage--corrupted stack?  Why--bug in Microsoft C? */
  1428. Xzooexit (1);
  1429. X}
  1430. END_OF_FILE
  1431. if test 9863 -ne `wc -c <'zoo.c'`; then
  1432.     echo shar: \"'zoo.c'\" unpacked with wrong size!
  1433. fi
  1434. # end of 'zoo.c'
  1435. fi
  1436. echo shar: End of archive 5 \(of 10\).
  1437. cp /dev/null ark5isdone
  1438. MISSING=""
  1439. for I in 1 2 3 4 5 6 7 8 9 10 ; do
  1440.     if test ! -f ark${I}isdone ; then
  1441.     MISSING="${MISSING} ${I}"
  1442.     fi
  1443. done
  1444. if test "${MISSING}" = "" ; then
  1445.     echo You have unpacked all 10 archives.
  1446.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1447. else
  1448.     echo You still need to unpack the following archives:
  1449.     echo "        " ${MISSING}
  1450. fi
  1451. ##  End of shell archive.
  1452. exit 0
  1453.